#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "MenuBar.h"

#include "Class.h"
#include "OrdColl.h"
#include "Clipper.h"
#include "Look.h"
#include "Box.h"
#include "Filler.h"
#include "Window.h"
#include "Buttons.h"
#include "PopupItem.h"
#include "Menu.h"
#include "ET_stdio.h"

//---- MenuItemSelector --------------------------------------------------------

class MenuItemSelector: public Command {
	MenuBar *mb;
	VObject *last;
public:
	MenuItemSelector(MenuBar*);
	void TrackFeedback(Point, Point, bool)
		{ }
	Command *TrackMouse(TrackPhase, Point, Point, Point);
};

MenuItemSelector::MenuItemSelector(MenuBar *m)
{
	mb= m;
	last= 0;
}

Command *MenuItemSelector::TrackMouse(TrackPhase atp, Point, Point, Point np)
{
	VObject *itemptr= mb->FindItem(np);
		
	switch (atp) {
	case eTrackPress:
		if (itemptr)
			itemptr->DoTrackMouse(eTrackPress, np);
		break;
	case eTrackMove:
		if (itemptr != last) {
			if (last)
				last->DoTrackMouse(eTrackExit, np);
			if (itemptr)
				itemptr->DoTrackMouse(eTrackPress, np);
			last= itemptr;
		} else if (itemptr)
			itemptr->DoTrackMouse(eTrackMove, np);
		break;
	case eTrackRelease:
		if (itemptr)
			itemptr->DoTrackMouse(eTrackRelease, np);
		return gNoChanges;
	case eTrackExit:
		if (itemptr)
			itemptr->DoTrackMouse(eTrackExit, np);
		return gNoChanges;
	case eTrackIdle:
		break;
	}
	return this;
}

//---- MenuBar -----------------------------------------------------------------

NewMetaImpl0(MenuBar,Box);

MenuBar::MenuBar(Collection *c) : Box(cIdNone, Point(2, 0), gPoint4,
										(VObjAlign)(eVObjVBase+eVObjHGapExpand))
{
	Add(mb= new HBox(gPoint0, (VObjAlign)(eVObjVCenter|eVObjHExpand), (SeqCollection*)c));
	help= new Filler(gPoint4, eVObjVFixed);
	help->Disable();
}

VObject *MenuBar::FindItem(Point p)
{
	VObjectIter next(mb);
	register VObject *vop;

	while (vop= next())
		if (vop->ContainsPoint(p))
			if (vop->IsKindOf(PullDownButton))
				return vop;
	return 0;
}

Menu *MenuBar::FindMenu(int id)
{
	VObjectIter next(mb);
	register VObject *vop;

	while (vop= next())
		if (vop->GetId() == id && vop->IsKindOf(PullDownButton))
			return ((PullDownButton*)vop)->MyMenu();
	return 0;
}

int MenuBar::CheckKey(Token &t)
{
	int cmd= cIdNone;
	VObjectIter next(mb);
	register VObject *vop;
	Manager *m= GetManager();

	while (vop= next()) {
		if (vop->IsKindOf(PullDownButton)) {
			PullDownButton *pdb= (PullDownButton*) vop;
			Menu *menu= pdb->MyMenu();
		
			if (m)
				menu->SetNextManager(m);
			else
				fprintf(stderr, "MenuBar::CheckKey: oops\n");
		
			cmd= pdb->MyMenu()->CheckKey(t);
			if (cmd != cIdNone) {
				pdb->Flush();
				return cmd;
			}
		}
	}
	return cIdNone;
}

Metric MenuBar::GetMinSize()
{
	Metric m(gLook->MenuBarLayout()->GetMinSize(this));
	SetFlag(eVObjHFixed, At(0)->TestFlag(eVObjHFixed));
	SetFlag(eVObjVFixed, At(0)->TestFlag(eVObjVFixed));
	return m;
}

void MenuBar::SetExtent(Point e)
{
	VObject::SetExtent(e);
	gLook->MenuBarLayout()->SetExtent(this, e);
}

void MenuBar::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	gLook->MenuBarLayout()->SetOrigin(this, at);
}

void MenuBar::Draw(Rectangle r)
{
	At(0)->DrawAll(r);
	gLook->MenuBarLayout()->Adorn(this, r, 0);
}

void MenuBar::AddMenu(Menu *pdm, PullDownButton *b)
{
	if (pdm) {
		PullDownButton *pdb= b;
		if (b == 0)
			pdb= new PullDownButton(pdm->GetId(), pdm);
		else
			pdb->SetId(pdm->GetId());
		if (mb->Size() <= 0) {
			mb->Add(pdb);
			mb->Add(help);
		} else {
			SeqCollection *s= mb->GetList();
			s->AddBeforePtr(pdb, help);
			pdb->SetContainer(mb);
			if (mb->IsOpen())
				pdb->Open();
		}
	}
}

void MenuBar::AddMenuRight(Menu *pdm, PullDownButton *b)
{
	if (pdm) {
		PullDownButton *pdb= b;
		if (b == 0)
			pdb= new PullDownButton(pdm->GetId(), pdm);
		else
			pdb->SetId(pdm->GetId());
		if (mb->Size() <= 0)
			mb->Add(help);
		mb->Add(pdb);
	}
}

Command *MenuBar::DispatchEvents(Point lp, Token &t, Clipper *vf)
{
	if (t.Code == eEvtLeftButton && t.Flags == 0) {
		Command *cmd= new MenuItemSelector(this);
		if (cmd && cmd != gNoChanges && vf)
			cmd= vf->TrackInContent(lp, t, cmd);
		return gNoChanges;
	}
	return CompositeVObject::DispatchEvents(lp, t, vf);
}

